package com.googlecode.animator.controller.mediators
{
	import com.googlecode.animator.model.ProjectSettingsProxy;
	import com.googlecode.data.ProjectConstants;
	import com.googlecode.interfaces.IPreview;
	import com.googlecode.player.Animator3DPlayer;
	import com.googlecode.player.events.XMLLoadableEvent;
	
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	
	import mx.containers.TitleWindow;
	import mx.controls.SWFLoader;
	import mx.core.Application;
	import mx.core.ScrollPolicy;
	import mx.events.CloseEvent;
	import mx.events.FlexEvent;
	import mx.events.ModuleEvent;
	import mx.managers.PopUpManager;
	import mx.managers.SystemManager;
	
	import org.puremvc.as3.multicore.interfaces.INotification;
	import org.puremvc.as3.multicore.interfaces.IProxy;
	import org.puremvc.as3.multicore.patterns.mediator.Mediator;

	public class PreviewProjectMediator extends Mediator
	{
		/**
		 * Name prefix used to create dynamic mediator names.
		 * Names will be appended by the INSTANCE_COUNT to create a unique mediator name. 
		 */
		protected static const NAME_PREFIX:String = "PreviewProjectMediator_";
		
		/**
		 * Amount by which to enlarge TitleWindow to enclose player. 
		 */
		protected static const PADDING:uint = 30;
		
		/**
		 * Counter indicating how many instances of this class have been created. 
		 */		
		protected static var INSTANCE_COUNT:uint = 0;
		
		/**
		 * Project XML. 
		 */
		protected var _projectXML:XML;
		
		/**
		 * Reference to the popup window. 
		 */
		protected var _window:TitleWindow;
		
		/**
		 * Reference to the SWFLoader that will load the player. 
		 */
		protected var _loader:SWFLoader;
		
		/**
		 * Reference to the system manager. 
		 */
		protected var _loaderManager:SystemManager;
		
		
		/**
		 * Constructor. 
		 * @param path
		 * 
		 */
		public function PreviewProjectMediator()
		{
			super(NAME_PREFIX + INSTANCE_COUNT);

			// update instance count so we obtain a unique name for each Mediator instance
			INSTANCE_COUNT++;
		}
		
		/**
		 * Links in with PureMVC framework. 
		 * 
		 */
		override public function onRegister():void
		{
			// create popup
			
			_projectXML = settings.getProjectXML();
			
			_window = new TitleWindow();
			_window.showCloseButton = true;
			_window.width = uint(_projectXML.stage.stageWidth) + PADDING;
			_window.height = uint(_projectXML.stage.stageHeight) + PADDING + 20;
			_window.addEventListener(CloseEvent.CLOSE, onClose);
			_window.verticalScrollPolicy = ScrollPolicy.OFF;
			_window.horizontalScrollPolicy = ScrollPolicy.OFF;
			
			PopUpManager.addPopUp(_window, Application.application.topMenu.parent, true);
			PopUpManager.centerPopUp(_window);
			
			// create loader
			
			_loader = new SWFLoader();
			_loader.addEventListener(Event.COMPLETE, onPreviewShellLoaded);
			_loader.addEventListener(IOErrorEvent.IO_ERROR, onError);
			_loader.load(ProjectConstants.PREVIEW_SWF_PATH);
		}
		
		/**
		 * Called when uses closes popup. 
		 * @param evt
		 * 
		 */
		protected function onClose(evt:CloseEvent):void
		{	
			var loadedApp:Application = Application(_loaderManager.application);
			
			if((loadedApp as IPreview).animator3DPlayer)
			{
				(loadedApp as IPreview).destroy();
			}
			
			_loader.source = null;
			
			PopUpManager.removePopUp(_window);
			facade.removeMediator(getMediatorName());
		}
		
		/**
		 * Preview shell loaded successfully. 
		 * @param evt
		 * 
		 */
		protected function onPreviewShellLoaded(evt:Event):void
		{
			_loaderManager = _loader.content as SystemManager;		
			_loaderManager.addEventListener(FlexEvent.APPLICATION_COMPLETE, onShellReady);
		}
		
		/**
		 * Gaurantees the Preview shell is ready. The player itself may not have loaded though.
		 * @param evt
		 * 
		 */
		protected function onShellReady(evt:FlexEvent):void
		{	
			
			
			var previewShell:Application = Application(_loaderManager.application);
			
			_window.addChild(previewShell);

			// test if animator3DPlayer has loaded
			if((previewShell as IPreview).animator3DPlayer == null)
			{
				// if animator3DPlayer is not ready, add an event listener
				(previewShell as IPreview).loader.addEventListener(ModuleEvent.READY, onPlayerReady);
			}else
			{
				// if the animator3DPlayer is ready, listen for the XMLLoadableEvent
				(previewShell as IPreview).animator3DPlayer.addEventListener(XMLLoadableEvent.NAME, onXMLReady);
				(previewShell as IPreview).startMVC();
			}
			
			
		} 
		
		/**
		 * Gaurantees the player is ready. 
		 * @param evt
		 * 
		 */
		protected function onPlayerReady(evt:ModuleEvent):void
		{
			var loadedApp:Application = Application(_loaderManager.application);

			(loadedApp as IPreview).loader.removeEventListener(ModuleEvent.READY, onPlayerReady);
			
			// listen for the XMLLoadableEvent
			(loadedApp as IPreview).animator3DPlayer.addEventListener(XMLLoadableEvent.NAME, onXMLReady);
			
			
		}
		
		/**
		 * Initiate the loading of the project. 
		 * 
		 */
		protected function onViewComplete(evt:FlexEvent):void
		{
			var loadedApp:Application = Application(_loaderManager.application);
			
			(loadedApp as IPreview).startMVC();
			//var loadedApp:Application = Application(_loaderManager.application);
			trace("!!!!!!!!!!!"+evt);
			// now listen for event indicating XML can be loaded
			//(loadedApp as IPreview).animator3DPlayer.addEventListener(XMLLoadableEvent.NAME, onXMLReady);
			
			// start the ball rolling
			/* (loadedApp as IPreview).startMVC();
			(loadedApp as IPreview).loadXML(_projectXML);

			loadedApp.width = uint(_projectXML.stage.stageWidth);
			loadedApp.height = uint(_projectXML.stage.stageHeight);

			_window.addChild(loadedApp); */
		}
		
		/**
		 * Load XML. 
		 * @param evt
		 * 
		 */
		protected function onXMLReady(evt:XMLLoadableEvent):void
		{
	
			var loadedApp:Application = Application(_loaderManager.application);
			(loadedApp as IPreview).animator3DPlayer.removeEventListener(XMLLoadableEvent.NAME, onXMLReady);
			
			// start the ball rolling
			//

			loadedApp.width = uint(_projectXML.stage.stageWidth);
			loadedApp.height = uint(_projectXML.stage.stageHeight);
			
			
			
			// at this point the preview shell is loaded and the Animator3DPlayer is loaded. The
			// viewport should be ready and the scene is created. Loading the XML causes a problem though?
			
			(loadedApp as IPreview).loadXML(_projectXML);
			//trace("load"+(((loadedApp as IPreview).animator3DPlayer) as Animator3DPlayer).view);
		}
		
		/**
		 * Error in loading player. 
		 * @param evt
		 * 
		 */
		protected function onError(evt:IOErrorEvent):void
		{
			
		}
		
		/**
		 * List notifications of interest. 
		 * @return 
		 * 
		 */
		override public function listNotificationInterests():Array
		{
			var list:Array = super.listNotificationInterests();
			
			//
			
			return list;
		}
		
		/**
		 * Handle notifications of interest. 
		 * @param notification
		 * 
		 */
		override public function handleNotification(notification:INotification):void
		{
			super.handleNotification(notification);
			
			//
		}
		
		/**
		 * Handles the project XML once it has been successfully loaded. 
		 * @param evt
		 * 
		 */
		/* protected function onProjectXMLLoaded(evt:Event):void
		{
			(evt.target as URLLoader).removeEventListener(Event.COMPLETE, onProjectXMLLoaded);
			(evt.target as URLLoader).removeEventListener(IOErrorEvent.IO_ERROR, onError);
			
			_projectXML = new XML(((evt.target) as URLLoader).data);
			
			// check that XML is legitimate
			if(_projectXML.@id != ProjectConstants.PROJECT_NAME)
			{
				facade.removeMediator(getMediatorName());
				
				return;
			}
			
			// update stage properties
			var stageObj:StagePropertiesVO = new StagePropertiesVO();
			stageObj.stageWidth = _projectXML.stage.stageWidth;
			stageObj.stageHeight = _projectXML.stage.stageHeight;
			
			sendNotification(Notifications.SET_STAGE_SIZE_MODEL, stageObj);
			sendNotification(Notifications.SET_WORK_AREA_VISIBLE, stageObj);
			
			var vVO:ViewportVO;
			
			for each(var viewport:XML in _projectXML.viewports.viewport)
			{
				vVO = new ViewportVO();
				vVO.fromXML(viewport);
				
				sendNotification(Notifications.ADD_VIEWPORT_MODEL, vVO);
			} 
			
		} */
		
		
		/**
		 * Handles the notification of the default viewports being added,
		 * which has to precede any attempt to load 3D assets. 
		 * 
		 */
		/* protected function handleDefaultViewportsAdded():void
		{
			// make sure the save path is set to the correct address

			
			var cameraVO:CameraVO;
			//sendNotification(Notifications.ADD_DEFAULT_CAMERAS, _projectXML);
			for each(var camera:XML in _projectXML.cameras.*)
			{
				if(camera.name() == ActualViewCameraVO.TYPE)
				{
					cameraVO = new ActualViewCameraVO();
					cameraVO.fromXML(camera);
					
					sendNotification(Notifications.ADD_CAMERA_MODEL, cameraVO as ActualViewCameraVO);
				}
				
				if(camera.name() == MainViewCameraVO.TYPE)
				{
					cameraVO = new MainViewCameraVO();
					cameraVO.fromXML(camera);
					
					sendNotification(Notifications.ADD_CAMERA_MODEL, cameraVO as MainViewCameraVO);
				}
				
				if(camera.name() == TopViewCameraVO.TYPE)
				{
					cameraVO = new TopViewCameraVO();
					cameraVO.fromXML(camera);
					
					sendNotification(Notifications.ADD_CAMERA_MODEL, cameraVO as TopViewCameraVO);
				}
				
				if(camera.name() == LeftViewCameraVO.TYPE)
				{
					cameraVO = new LeftViewCameraVO();
					cameraVO.fromXML(camera);
					
					sendNotification(Notifications.ADD_CAMERA_MODEL, cameraVO as LeftViewCameraVO);
				}
				
				if(camera.name() == FrontViewCameraVO.TYPE)
				{
					cameraVO = new FrontViewCameraVO();
					cameraVO.fromXML(camera);
					
					sendNotification(Notifications.ADD_CAMERA_MODEL, cameraVO as FrontViewCameraVO);
				}
			}

			// now add everything else
			var globalMarker:GlobalMarkerVO;
			
			for each(var gMarker:XML in _projectXML.globalMarkers.globalMarker)
			{
				globalMarker = new GlobalMarkerVO();
				globalMarker.fromXML(gMarker);
				
				sendNotification(Notifications.ADD_GLOBAL_MARKER, globalMarker);
			}
			
			var o3D:Object3DVO
			
			for each(var object3D:XML in _projectXML.objects3D.*)
			{
				if(object3D.name() == CameraProxyVO.TYPE)
				{
					o3D = new CameraProxyVO();
					o3D.fromXML(object3D);
					
					//_objectsList.push(o3D);
					sendNotification(Notifications.ADD_OBJECT3D_MODEL, o3D as CameraProxyVO);	
				}
				
				if(object3D.name() == TargetProxyVO.TYPE)
				{
					o3D = new TargetProxyVO();
					o3D.fromXML(object3D);
					
					//_objectsList.push(o3D);
					sendNotification(Notifications.ADD_OBJECT3D_MODEL, o3D as TargetProxyVO);	
				}
				
				if(object3D.name() == SphereVO.TYPE)
				{
					o3D = new SphereVO();
					o3D.fromXML(object3D);
					
					//_objectsList.push(o3D);
					sendNotification(Notifications.ADD_OBJECT3D_MODEL, o3D as SphereVO);
				}
				
				if(object3D.name() == PlaneVO.TYPE)
				{
					o3D = new PlaneVO();
					o3D.fromXML(object3D);
					
					//_objectsList.push(o3D);
					sendNotification(Notifications.ADD_OBJECT3D_MODEL, o3D as PlaneVO);
				} 
				
				if(object3D.name() == CubeVO.TYPE)
				{
					o3D = new CubeVO();
					o3D.fromXML(object3D);
				
					//_objectsList.push(o3D);
					sendNotification(Notifications.ADD_OBJECT3D_MODEL, o3D as CubeVO);	
				}

			}
			
			//sendNotification(Notifications.OBJECT3D_SELECTED, o3D.name);
			
			facade.removeMediator(getMediatorName());
		} */
		
		/**
		 * Returns typed reference to model. 
		 * @return 
		 * 
		 */
		protected function get settings():ProjectSettingsProxy
		{
			var proxy:IProxy = facade.retrieveProxy(ProjectSettingsProxy.NAME);
			
			return proxy as ProjectSettingsProxy;
		}
	}
	
}